﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Platform.ObjectModel.Design;
using System.Text.RegularExpressions;

namespace Platform.ObjectModel.Validation
{
	public class DefaultValidatorFactory : IValidatorFactory
	{

		#region IValidatorFactory Members

		public IDataObjectValidator Create( Schema schema )
		{

			return new Validator( schema.Fields, schema.Rules );

			//List<RuleBase> rules = new List<RuleBase>( schema.Fields.Count + schema.Rules.Count );

			//// Adiciona as regras de cada campo
			//rules.AddRange( schema.Fields.SelectMany( f => f.Rules ) );
			//// Adiciona as regras do schema do documento
			//rules.AddRange( schema.Rules );
		}

		#endregion

		private sealed class Validator : IDataObjectValidator
		{
			/// <summary>
			/// Regras dos campos. Podem ser executadas em paralelo
			/// </summary>
			private IEnumerable<FieldDescriptor> fields;

			/// <summary>
			/// Regra que necessitam ser executadas em sequência
			/// </summary>
			private IEnumerable<RuleBase> dependentRules;

			/// <summary>
			/// 
			/// </summary>
			/// <param name="fields"></param>
			/// <param name="dependentRules"></param>
			internal Validator( IEnumerable<FieldDescriptor> fields, IEnumerable<RuleBase> dependentRules )
			{
				this.fields = fields;
				this.dependentRules = dependentRules;
			}

			#region IDataObjectValidator Members

			public ValidationResult Validate( DataObjectFlake data, DocumentContext context )
			{
				// Valida as regras dos campos
				( from field in this.fields
				  from rule in field.Rules
				  select new
				  {
					  Field = field,
					  Rule = rule
				  } )
				  .Each(
					pair =>
					{
						bool isValid = pair.Rule.Validate( data.Get(pair.Field.QualifiedName), context );
						if ( !isValid )
						{
							// Adiciona a mensagem de erro
							// StringTemplate http://visualstudiogallery.msdn.microsoft.com/5ca30e58-96b4-4edf-b95e-3030daf474ff

							// TODO : Adicionar mensagem de validação
						}
					} );

				// Executa as demais regras
				if ( context.Result.IsValid )
				{
					this.dependentRules
						.DoWhile(
							rule =>
							{
								bool isValid = rule.Validate( data, context );
								if ( !isValid )
								{
									// Adiciona a mensagem de erro
									// StringTemplate http://visualstudiogallery.msdn.microsoft.com/5ca30e58-96b4-4edf-b95e-3030daf474ff
								}
								return isValid;
							} );
				}

				return context.Result;
			}

			#endregion
		}

		//private sealed class Validator : IDataObjectValidator
		//{
		//    /// <summary>
		//    /// Regra que podem ser executadas em qualquer ordem que não afeta a execução das outras regas
		//    /// </summary>
		//    private IEnumerable<RuleBase> anyOrder;

		//    /// <summary>
		//    /// Regras que somente podem ser executadas se o processamento anterior está válido
		//    /// </summary>
		//    private IEnumerable<RuleBase> dependentRules;

		//    public Validator( IEnumerable<RuleBase> anyOrder, IEnumerable<RuleBase> dependentRules )
		//    {
		//        this.anyOrder = anyOrder ?? Enumerable.Empty<RuleBase>();
		//        this.dependentRules = dependentRules ?? Enumerable.Empty<RuleBase>();
		//    }

		//    #region IDataObjectValidator Members

		//    public ValidationResult Validate( DataObjectFlake data, DocumentContext context )
		//    {
		//        // Poderia executar em paralelo
		//        this.anyOrder.Each( rule => this.ExecuteRule( rule, data, context ) );
				
		//        // Executa sempre em sequencia
		//        this.dependentRules
		//            .DoWhile(
		//                rule =>
		//                {
		//                    this.ExecuteRule( rule, data, context );
		//                    return context.Result.IsValid;
		//                } );

		//        return context.Result;
		//    }

		//    #endregion

		//    private void ExecuteRule( RuleBase rule, DataObjectFlake data, DocumentContext context )
		//    {
		//        bool isValid = rule.Validate( data, context );
		//        if ( !isValid )
		//        {
		//            // Adiciona a mensagem de erro
		//            if ( !String.IsNullOrEmpty( rule.ErrorMessageFormat ) )
		//            {

		//            }
		//        }
		//    }
		//}
	}


	public class StringTemplate
	{
		private static readonly Regex parser = new Regex( @"{#(?<prop>.+)}", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Multiline );

		public StringTemplate( string template )
		{
			this.Template = template;
		}

		public string Template
		{
			get;
			private set;
		}


		public string Apply( IDictionary<string, object> values )
		{
			if ( String.IsNullOrEmpty( this.Template ) )
				return String.Empty;

			
			StringBuilder content = new StringBuilder( this.Template.Length );



			return content.ToString();
		}

		protected List<TemplateWriter> ParseTemplate()
		{
			return null;
			//if ( this.templateSteps == null )
			//{
			//    var steps = new List<TemplateWriter>();

			//    var matches = parser.Matches( this.Template );
			//    int lastIndex = 0;
			//    for ( int index = 0; index < matches.Count; index++ )
			//    {
			//        var match = matches[ index ];
			//        var propertyName = match.Groups[ "prop" ].Value;

			//        // Adiciona o conteúdo string
			//        steps.Add( this.MakeWriteString( this.Template.Substring( lastIndex, match.Index ) ) );
			//        lastIndex = match.Index;
			//        // Adiciona a propriedade

			//    }

			//    // Adiciona a última string
			//    steps.Add( this.MakeWriteString( this.Template.Substring( lastIndex, this.Template.Length - lastIndex ) ) );

			//    this.templateSteps = steps;
			//}
			//return this.templateSteps;
		}

		//private TemplateWriter MakeWriteString( string content )
		//{

		//}

		//private TemplateWriter MakeGetProperty( string propertyName )
		//{
		//    // ( content, values ) => Convert.ToString(((...)values["property"]).Property)

		//}
	}

	public delegate void TemplateWriter(StringBuilder content, IDictionary<string,object> values);

	//public class RuleBasedValidator : IDataObjectValidator
	//{

	//    internal RuleBasedValidator( IEnumerable<RuleBase> rules )
	//    {
	//        this.Rules = rules;
	//    }

	//    public IEnumerable<RuleBase> Rules
	//    { get; private set; }

	//    #region IDataObjectValidator Members

	//    public ValidationResult Validate( DataObjectFlake data, DocumentContext context )
	//    {
	//        throw new NotImplementedException();
	//    }

	//    #endregion
	//}
}
